﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel.Syndication;
using System.Web.Mvc;
using Nop.Core;
using Nop.Core.Caching;
using Nop.Core.Domain;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.Localization;
using Nop.Core.Domain.Media;
using Nop.Core.Domain.Orders;
using Nop.Services.Catalog;
using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.Directory;
using Nop.Services.Helpers;
using Nop.Services.Localization;
using Nop.Services.Media;
using Nop.Services.Messages;
using Nop.Services.Orders;
using Nop.Services.Security;
using Nop.Services.Seo;
using Nop.Services.Tax;
using Nop.Web.Extensions;
using Nop.Web.Framework;
using Nop.Web.Framework.Controllers;
using Nop.Web.Framework.Security;
using Nop.Web.Framework.UI.Captcha;
using Nop.Web.Infrastructure.Cache;
using Nop.Web.Models.Catalog;
using Nop.Web.Models.Media;
using Nop.Services.Logging;
using Telerik.Web.Mvc;

using System.Web.Security;
using Nop.Services.Authentication;

namespace Nop.Web.Controllers
{
    public class ShopController : BaseNopController
    {

        #region Fields

        private readonly ICategoryService _categoryService;
        private readonly IManufacturerService _manufacturerService;
        private readonly IProductService _productService;
        private readonly IProductTemplateService _productTemplateService;
        private readonly ICategoryTemplateService _categoryTemplateService;
        private readonly IManufacturerTemplateService _manufacturerTemplateService;
        private readonly IProductAttributeService _productAttributeService;
        private readonly IProductAttributeParser _productAttributeParser;
        private readonly IWorkContext _workContext;
        private readonly ITaxService _taxService;
        private readonly ICurrencyService _currencyService;
        private readonly IPictureService _pictureService;
        private readonly ILocalizationService _localizationService;
        private readonly IPriceCalculationService _priceCalculationService;
        private readonly IPriceFormatter _priceFormatter;
        private readonly IWebHelper _webHelper;
        private readonly ISpecificationAttributeService _specificationAttributeService;
        private readonly ICustomerContentService _customerContentService;
        private readonly IDateTimeHelper _dateTimeHelper;
        private readonly IShoppingCartService _shoppingCartService;
        private readonly IRecentlyViewedProductsService _recentlyViewedProductsService;
        private readonly ICompareProductsService _compareProductsService;
        private readonly IWorkflowMessageService _workflowMessageService;
        private readonly IProductTagService _productTagService;
        private readonly IOrderReportService _orderReportService;
        private readonly IGenericAttributeService _genericAttributeService;
        private readonly IBackInStockSubscriptionService _backInStockSubscriptionService;
        private readonly IPermissionService _permissionService;
        private readonly IDownloadService _downloadService;
        private readonly ICustomerActivityService _customerActivityService;

        private readonly MediaSettings _mediaSettings;
        private readonly CatalogSettings _catalogSettings;
        private readonly ShoppingCartSettings _shoppingCartSettings;
        private readonly StoreInformationSettings _storeInformationSettings;
        private readonly LocalizationSettings _localizationSettings;
        private readonly CustomerSettings _customerSettings;
        private readonly ICacheManager _cacheManager;
        private readonly CaptchaSettings _captchaSettings;
        private readonly IOrderService _orderService;
        private readonly IShopRecommendService _era_ShopRecommendService;
        private readonly IAuthenticationService _authenticationService;
        #endregion

        #region Constructors

        public ShopController(ICategoryService categoryService,
            IManufacturerService manufacturerService, IProductService productService,
            IProductTemplateService productTemplateService,
            ICategoryTemplateService categoryTemplateService,
            IManufacturerTemplateService manufacturerTemplateService,
            IProductAttributeService productAttributeService, IProductAttributeParser productAttributeParser,
            IWorkContext workContext, ITaxService taxService, ICurrencyService currencyService,
            IPictureService pictureService, ILocalizationService localizationService,
            IPriceCalculationService priceCalculationService, IPriceFormatter priceFormatter,
            IWebHelper webHelper, ISpecificationAttributeService specificationAttributeService,
            ICustomerContentService customerContentService, IDateTimeHelper dateTimeHelper,
            IShoppingCartService shoppingCartService,
            IRecentlyViewedProductsService recentlyViewedProductsService, ICompareProductsService compareProductsService,
            IWorkflowMessageService workflowMessageService, IProductTagService productTagService,
            IOrderReportService orderReportService, IGenericAttributeService genericAttributeService,
            IBackInStockSubscriptionService backInStockSubscriptionService,
            IPermissionService permissionService, IDownloadService downloadService,
            ICustomerActivityService customerActivityService,
            MediaSettings mediaSettings, CatalogSettings catalogSettings,
            ShoppingCartSettings shoppingCartSettings, StoreInformationSettings storeInformationSettings,
            LocalizationSettings localizationSettings, CustomerSettings customerSettings,
            CaptchaSettings captchaSettings,
            ICacheManager cacheManager,
            IOrderService orderService,
            IShopRecommendService era_ShopRecommendService,
            IAuthenticationService authenticationService)
        {
            this._categoryService = categoryService;
            this._manufacturerService = manufacturerService;
            this._productService = productService;
            this._productTemplateService = productTemplateService;
            this._categoryTemplateService = categoryTemplateService;
            this._manufacturerTemplateService = manufacturerTemplateService;
            this._productAttributeService = productAttributeService;
            this._productAttributeParser = productAttributeParser;
            this._workContext = workContext;
            this._taxService = taxService;
            this._currencyService = currencyService;
            this._pictureService = pictureService;
            this._localizationService = localizationService;
            this._priceCalculationService = priceCalculationService;
            this._priceFormatter = priceFormatter;
            this._webHelper = webHelper;
            this._specificationAttributeService = specificationAttributeService;
            this._customerContentService = customerContentService;
            this._dateTimeHelper = dateTimeHelper;
            this._shoppingCartService = shoppingCartService;
            this._recentlyViewedProductsService = recentlyViewedProductsService;
            this._compareProductsService = compareProductsService;
            this._workflowMessageService = workflowMessageService;
            this._productTagService = productTagService;
            this._orderReportService = orderReportService;
            this._genericAttributeService = genericAttributeService;
            this._backInStockSubscriptionService = backInStockSubscriptionService;
            this._permissionService = permissionService;
            this._downloadService = downloadService;
            this._customerActivityService = customerActivityService;


            this._mediaSettings = mediaSettings;
            this._catalogSettings = catalogSettings;
            this._shoppingCartSettings = shoppingCartSettings;
            this._storeInformationSettings = storeInformationSettings;
            this._localizationSettings = localizationSettings;
            this._customerSettings = customerSettings;
            this._captchaSettings = captchaSettings;

            this._cacheManager = cacheManager;
            this._orderService = orderService;
            this._era_ShopRecommendService = era_ShopRecommendService;
            this._authenticationService = authenticationService;
        }

        #endregion

        [NonAction]
        protected IEnumerable<ProductOverviewModel> PrepareProductOverviewModels(IEnumerable<Product> products,
            bool preparePriceModel = true, bool preparePictureModel = true,
            int? productThumbPictureSize = null, bool prepareSpecificationAttributes = false,
            bool forceRedirectionAfterAddingToCart = false,
            bool prepareManufacturer = false)
        {
            if (products == null)
                throw new ArgumentNullException("products");

            //performance optimization. let's load all variants at one go
            var allVariants = _productService.GetProductVariantsByProductIds(products.Select(x => x.Id).ToArray());


            var models = new List<ProductOverviewModel>();
            foreach (var product in products)
            {
                var model = new ProductOverviewModel()
                {
                    Id = product.Id,
                    Name = product.GetLocalized(x => x.Name),
                    ShortDescription = product.GetLocalized(x => x.ShortDescription),
                    FullDescription = product.GetLocalized(x => x.FullDescription),
                    SeName = product.GetSeName(),
                    TradingVolume = product.TradingVolume,
                    ClickNumber = product.ClickNumber
                };
                //price
                if (preparePriceModel)
                {
                    #region Prepare product price

                    var priceModel = new ProductOverviewModel.ProductPriceModel();

                    //var productVariants = _productService.GetProductVariantsByProductId(product.Id);
                    //we use already loaded variants
                    var productVariants = allVariants.Where(x => x.ProductId == product.Id).ToList();

                    switch (productVariants.Count)
                    {
                        case 0:
                            {
                                //no variants
                                priceModel.OldPrice = null;
                                priceModel.Price = null;
                            }
                            break;
                        default:
                            {

                                if (_permissionService.Authorize(StandardPermissionProvider.DisplayPrices))
                                {
                                    //calculate for the maximum quantity (in case if we have tier prices)
                                    decimal? minimalPrice = null;
                                    var productVariant = _priceCalculationService.GetProductVariantWithMinimalPrice(productVariants, _workContext.CurrentCustomer, true, int.MaxValue, out minimalPrice);

                                    if (!productVariant.CustomerEntersPrice)
                                    {
                                        if (productVariant.CallForPrice)
                                        {
                                            priceModel.OldPrice = null;
                                            priceModel.Price = _localizationService.GetResource("Products.CallForPrice");
                                        }
                                        else if (minimalPrice.HasValue)
                                        {
                                            //calculate prices
                                            decimal taxRate = decimal.Zero;
                                            decimal oldPriceBase = _taxService.GetProductPrice(productVariant, productVariant.OldPrice, out taxRate);
                                            decimal finalPriceBase = _taxService.GetProductPrice(productVariant, minimalPrice.Value, out taxRate);

                                            decimal oldPrice = _currencyService.ConvertFromPrimaryStoreCurrency(oldPriceBase, _workContext.WorkingCurrency);
                                            decimal finalPrice = _currencyService.ConvertFromPrimaryStoreCurrency(finalPriceBase, _workContext.WorkingCurrency);

                                            //do we have tier prices configured?
                                            var tierPrices = new List<TierPrice>();
                                            if (productVariant.HasTierPrices)
                                            {
                                                tierPrices.AddRange(productVariant.TierPrices
                                                    .OrderBy(tp => tp.Quantity)
                                                    .ToList()
                                                    .FilterForCustomer(_workContext.CurrentCustomer)
                                                    .RemoveDuplicatedQuantities());
                                            }
                                            bool displayFromMessage =
                                                //When there is just one tier (with  qty 1), there are no actual savings in the list.
                                                (tierPrices.Count > 0 && !(tierPrices.Count == 1 && tierPrices[0].Quantity <= 1)) ||
                                                //we have more than one variant
                                                (productVariants.Count > 1);
                                            if (displayFromMessage)
                                            {
                                                priceModel.OldPrice = null;
                                                //priceModel.Price = String.Format(_localizationService.GetResource("Products.PriceRangeFrom"), _priceFormatter.FormatPrice(finalPrice));
                                                priceModel.Price = Math.Round(finalPrice, 0).ToString();
                                            }
                                            else
                                            {
                                                if (finalPriceBase != oldPriceBase && oldPriceBase != decimal.Zero)
                                                {
                                                    priceModel.OldPrice = _priceFormatter.FormatPrice(oldPrice);
                                                    //priceModel.Price = _priceFormatter.FormatPrice(finalPrice);
                                                    priceModel.Price = Math.Round(finalPrice, 0).ToString();
                                                }
                                                else
                                                {
                                                    priceModel.OldPrice = null;
                                                    //priceModel.Price = _priceFormatter.FormatPrice(finalPrice);//old
                                                    priceModel.Price = Math.Round(finalPrice, 0).ToString();
                                                }
                                            }
                                        }
                                        else
                                        {
                                            //Actually it's not possible (we presume that minimalPrice always has a value)
                                            //We never should get here
                                            Debug.WriteLine(string.Format("Cannot calculate minPrice for product variant #{0}", productVariant.Id));
                                        }
                                    }
                                }
                                else
                                {
                                    //hide prices
                                    priceModel.OldPrice = null;
                                    priceModel.Price = null;
                                }
                            }
                            break;
                    }

                    //'add to cart' button
                    switch (productVariants.Count)
                    {
                        case 0:
                            {
                                // no variants
                                priceModel.DisableBuyButton = true;
                                priceModel.AvailableForPreOrder = false;
                            }
                            break;
                        case 1:
                            {

                                //only one variant
                                var productVariant = productVariants[0];
                                priceModel.DisableBuyButton = productVariant.DisableBuyButton || !_permissionService.Authorize(StandardPermissionProvider.EnableShoppingCart);
                                if (!_permissionService.Authorize(StandardPermissionProvider.DisplayPrices))
                                {
                                    priceModel.DisableBuyButton = true;
                                }
                                priceModel.AvailableForPreOrder = productVariant.AvailableForPreOrder;
                            }
                            break;
                        default:
                            {
                                //multiple variants
                                priceModel.DisableBuyButton = true;
                                priceModel.AvailableForPreOrder = false;
                            }
                            break;
                    }

                    priceModel.ForceRedirectionAfterAddingToCart = forceRedirectionAfterAddingToCart;
                    model.ProductPrice = priceModel;
                    #endregion
                }

                //picture
                if (preparePictureModel)
                {
                    #region Prepare product picture

                    //If a size has been set in the view, we use it in priority
                    int pictureSize = productThumbPictureSize.HasValue ? productThumbPictureSize.Value : _mediaSettings.ProductThumbPictureSize;
                    //prepare picture model
                    var defaultProductPictureCacheKey = string.Format(ModelCacheEventConsumer.PRODUCT_DEFAULTPICTURE_MODEL_KEY, product.Id, pictureSize, true, _workContext.WorkingLanguage.Id, _webHelper.IsCurrentConnectionSecured());
                    model.DefaultPictureModel = _cacheManager.Get(defaultProductPictureCacheKey, () =>
                    {
                        var picture = product.GetDefaultProductPicture(_pictureService);
                        var pictureModel = new PictureModel()
                        {
                            ImageUrl = _pictureService.GetPictureUrl(picture, pictureSize),
                            FullSizeImageUrl = _pictureService.GetPictureUrl(picture),
                            Title = string.Format(_localizationService.GetResource("Media.Product.ImageLinkTitleFormat"), model.Name),
                            AlternateText = string.Format(_localizationService.GetResource("Media.Product.ImageAlternateTextFormat"), model.Name)
                        };
                        return pictureModel;
                    });

                    #endregion
                }

                //specs
                if (prepareSpecificationAttributes)
                {
                    //specs for comparing
                    model.SpecificationAttributeModels = PrepareProductSpecificationModel(product);
                }

                if (prepareManufacturer)
                {
                    if (product.ProductManufacturers.ToList().Count > 0)
                    {
                        model.Manufacturer = product.ProductManufacturers.FirstOrDefault().Manufacturer;
                    }
                }

                models.Add(model);
            }
            return models;
        }

        [NonAction]
        protected IList<ProductSpecificationModel> PrepareProductSpecificationModel(Product product)
        {
            if (product == null)
                throw new ArgumentNullException("product");

            string cacheKey = string.Format(ModelCacheEventConsumer.PRODUCT_SPECS_MODEL_KEY, product.Id, _workContext.WorkingLanguage.Id);
            return _cacheManager.Get(cacheKey, () =>
            {
                var model = _specificationAttributeService.GetProductSpecificationAttributesByProductId(product.Id, null, true)
                   .Select(psa =>
                   {
                       return new ProductSpecificationModel()
                       {
                           SpecificationAttributeId = psa.SpecificationAttributeOption.SpecificationAttributeId,
                           SpecificationAttributeName = psa.SpecificationAttributeOption.SpecificationAttribute.GetLocalized(x => x.Name),
                           SpecificationAttributeOption = psa.SpecificationAttributeOption.GetLocalized(x => x.Name)
                       };
                   }).ToList();
                return model;
            });
        }


        //
        // GET: /shop/
        public ActionResult shop(int id)
        {
            //根据id找到这家店铺
            var shop = _manufacturerService.GetManufacturerById(id);
            if (shop == null)
            {
                return RedirectToAction("Index", "Home");
            }
            ViewBag.shopId = id;
            return View(shop);
        }


        //
        // GET: /shop_buy/
        public ActionResult shop_buy(int productId=0)
        {
            //更新产品点击量
            if (productId != 0)
            {
                Product pro = _productService.GetProductById(productId);
                pro.ClickNumber = pro.ClickNumber + 1;
                _productService.UpdateProduct(pro);
                //根据产品id找到这家店铺以及产品信息
                ProductManufacturer pm = _manufacturerService.GetProductManufacturerById(productId, true);
                if (pm != null)
                {
                    //添加到集合便于转换
                    List<Product> products = new List<Product>();

                    products.Add(pm.Product);
                    ProductOverviewModel poEntity = PrepareProductOverviewModels(products).FirstOrDefault();



                    ViewBag.ProductOverviewModel = poEntity;
                    ViewBag.ManufacturerModel = pm.Manufacturer;
                }
                ViewBag.shopId = pm.Manufacturer.Id;
            }
            ViewBag.productId = productId;
            return View();
        }

        //
        // GET: /shop_list/
        public ActionResult shop_list()
        {
            
            //获取每个菜系推荐的店铺根据添加时间倒序
            var listModel = _categoryService.GetReCategorys()
                .Select(x =>
                {
                    var catModel = x.ToModel();
                    catModel.ManuFactCount = _manufacturerService.GetTotalNumberByCategoryID(x.Id);
                    return catModel;

                })
                .ToList();

            //获取推荐8家店铺
            var listManufactureOne = _manufacturerService.GetAllManufacturers(null, 0, 8, true).Select(x =>
            {
                var catModel = x.ToModel();
                return catModel;

            }).ToList();
            //获取推荐店铺250家
            var listManufactureTwo = _manufacturerService.GetAllManufacturers(null, 0, 250, true).Select(x =>
            {
                var catModel = x.ToModel();
                catModel.Products = PrepareProductOverviewModels(_manufacturerService.GetProductsFoodByManufacturerId(catModel.Id).Take(7)).ToList();
               
                Category category = _categoryService.GetCategoryById(x.CategoryId);
                if (category != null)
                    catModel.CategoryName = category.Name;
                return catModel;

            }).ToList();

            ViewBag.listModel_v = listModel;
            ViewBag.listManufactureOne_v = listManufactureOne;
            ViewBag.listManufactureTwo_v = listManufactureTwo;

            return View(ViewBag);
        }

        //店铺推荐
        public JsonResult ShopRecommend(int shopId)
        {
            string msg = "0";//0→插入失败、1→推荐成功、2→已经推荐过了、3→未登录

            //获取登录的用户
            var customer = _authenticationService.GetAuthenticatedCustomer();
            if (customer != null)
            {
                //1、根据用户id和店铺id到数据库中查这条数据是否存在
                //1.1、存在→证明推荐过了。不能再推荐
                //1.2、不存在，向数据库中插入一条数据，同时推荐次数加1
                ShopRecommend entity = _era_ShopRecommendService.GetEntityByFunc(era => era.UserId == customer.Id && era.RecommendId == shopId  && era.RecommendType == 2);
                if (entity == null)
                {
                    entity = new ShopRecommend();
                    entity.IpAddress = Request.UserHostAddress;
                    entity.RecommendId = shopId;
                    entity.RecommendType = 2;
                    entity.UserId = customer.Id;
                    entity.CreatedOnUtc = DateTime.Now;
                    entity.Deleted = false;
                    _era_ShopRecommendService.InsertEntity(entity);
                    if (entity.Id > 0)
                    {
                        msg = "1";
                        //推荐次数+1
                        _manufacturerService.UpdateRecommendCount(shopId);
                    }
                }
                else
                {
                    msg = "2";
                }
            }
            else
            {
                msg = "3";
            }
            return Json(new { msg = msg });
        }
    }
}
